#include "gtlGameObject.h"
#include "gtlCore.h"
#include <gtl/gtlStructures.h>
#include <gtl/gtlFormats.h>

namespace GTL { namespace Engine {

	State* GameObject::GetState( const char* name )
	{
		return 0; /// TODO: Finish me
	}

	void GameObject::SwitchIntoState( const char* state )
	{
		AutoMember* children = mMembers;

		if (mCurrentState) /// Check siblings first
		  children = mCurrentState->ParentMember->Children;

		for (GTL::AutoMembers::AutoMember* i=children; i; i = i->NextSibling)
		{
			if (((StateHolder*)i)->StateName == state && i != (AutoMember*)mCurrentState)
			{
				mNextState = (StateHolder*)i;
				return;
			}
		}

		if (mCurrentState)
			children = mCurrentState->Children;
		else
			return;
		
		for (GTL::AutoMembers::AutoMember* i=children; i; i = i->NextSibling)
		{
			if (((StateHolder*)i)->StateName == state)
			{
				mNextState = (StateHolder*)i;
				return;
			}
		}
	}

	void GameObject::SwitchToParentState()
	{
		if (!mCurrentState)
		{
			Backend->LogError("Cannot go up from main object code!");
			return;
		}

		StateHolder* par = mCurrentState->GetParentState();
		if (par)
			mNextState = par;
	}

	void GameObject::SwitchState( StateHolder* i )
	{
		Event::EventHandler* switchEvent = 0;
		if (mCurrentState)
		{
			switchEvent = mCurrentState->GetEvent("Leave", true);
			if (switchEvent)
				Event::CallEvent(switchEvent, 0, 0);
		}

		mCurrentState = i;

		switchEvent = mCurrentState->GetEvent("Enter", true);
		if (switchEvent)
			Event::CallEvent(switchEvent, 0, 0);
	}

	int GameObject::OnUpdate( float dt )
	{
		if (mNextState != mCurrentState)
		{
			SwitchState(mNextState);
		}
		return CallEvent("Update", dt*TimeDilation);
	}

	int GameObject::OnDraw( float dt )
	{
		return CallEvent("Draw", dt);
	}

	int GameObject::OnEvent( GameEvent ev )
	{
		return CallEvent("Event", &ev);
	}

	Event::EventHandler* GameObject::GetEventHandler( const char* name )
	{
		if (!mCurrentState)
		{
			for (GTL::AutoMembers::AutoMember* i=mRootAutoMember.Children; i; i = i->NextSibling)
			{
				if (i->GetType() == 'even')
				{
					Event* ev = (Event*)i;
					if (ev->EventName == name)
						return &ev->Handler;
				}
			}
			return 0;
		}
		else
			return mCurrentState->GetEvent(name, false);
	}

	GameObject* GameObject::ProduceFromFile( const char* filename )
	{
		GTL::Utilities::AutoPointer<GTL::Structures::DataNode> node = GTL::Formats::LoadNodeFromFile(filename);
		if (!node) return 0;

		GameObject* obj = (GameObject*)GTL::Producer::ProduceType(node->GetElementSafe("type")->String.c_str());
		if (!obj) return 0;

		for (GTL::AutoMembers::AutoMember* member = obj->mMembers; member; member = member->Next)
		{
			if (member->Is('prop'))
			{
				Property* prop = (Property*)member;
				const GTL::Structures::DataNode* prop_node = node->GetElement(prop->GetName());
				if (prop_node)
				{
					prop->SetFromNode(prop_node);
					prop->MarkClean();
				}
			}
		}

		return obj;
	}

	int GameObject::CallEventVarArgs( const char* name, const GTL::Functions::VariableVariant* args, size_t argc, Event::EventHandler* handler /*= 0*/ )
	{
		if (!handler)
			handler = GetEventHandler(name);
		if (!handler) return -1;

		return Event::CallEvent(handler, args, argc);
	}

	int GameObject::CallEvent( const char* name )
	{
		Event::EventHandler* handler = GetEventHandler(name);
		if (!handler) return -1;

		return CallEventVarArgs(0, 0, 0, handler);
	}
}}